Imports System
Imports System.ComponentModel.Composition
Imports Contracts
Imports System.Reflection
Imports Microsoft.WindowsAPICodePack
Imports Microsoft.WindowsAPICodePack.Dialogs
Imports System.ComponentModel
Imports System.Linq
Imports Windows7.Location
Imports System.Xml
Imports System.Xml.Linq
Imports System.Windows.Forms
Imports MefTZAddin.interop

<WpfServiceMetadata("TZAddin")> _
Public Class TZAddinImpl
    Implements IWpfService
    Implements INotifyPropertyChanged

    Private _status As String

    Private WithEvents gps As LatLongLocationProvider
    Public Event StatusUpdated As EventHandler Implements IWpfService.StatusUpdated
    Private tzPicker As New TimezonePickerDialog()

    Private _optionsUI As New TZUserControl()

    Public Sub New()
        Console.WriteLine("TZ Changer starting up!")
    End Sub

#Region "Basic addin stuff"
    Public ReadOnly Property OptionsUserControl() As System.Windows.Controls.UserControl Implements IWpfService.OptionsUserControl
        Get
            Return _optionsUI
        End Get
    End Property

    Public ReadOnly Property Name() As String Implements IWpfService.Name
        Get
            Return "Time zone changer"
        End Get
    End Property

    Public ReadOnly Property AddinIconUri() As Uri Implements IWpfService.AddinIconUri
        Get
            Dim u As String = CreateResourceUri("Globe.png")

            Return New Uri(u)
        End Get
    End Property

    Private Function CreateResourceUri(ByVal name As String) As String
        Dim a As Assembly = Assembly.GetExecutingAssembly()
        Return String.Format("pack://application:,,,/{0};component/Resources/{1}", a.GetName().Name, name)
    End Function

    Public ReadOnly Property Description() As String Implements IWpfService.Description
        Get
            Return "Change the system time zone based on your location"
        End Get
    End Property

    Public ReadOnly Property Author() As String Implements IWpfService.Author
        Get
            Return "Arian T. Kulp"
        End Get
    End Property

    Public ReadOnly Property Version() As Version Implements IWpfService.Version
        Get
            Return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version
        End Get
    End Property

    Public ReadOnly Property AuthorUri() As Uri Implements IWpfService.AuthorUri
        Get
            Return New Uri("http://www.ariankulp.com/")
        End Get
    End Property

    Public ReadOnly Property UpdateUri() As Uri Implements IWpfService.UpdateUri
        Get
            Return New Uri("http://www.ariankulp.com/downloads/")
        End Get
    End Property

    Public Property Status() As String Implements IWpfService.Status
        Get
            Return _status
        End Get
        Set(ByVal value As String)
            If value <> _status Then
                _status = value

                OnPropertyChanged("Status")

                RaiseEvent StatusUpdated(Me, Nothing)
            End If
        End Set
    End Property

    Public Sub Initialize() Implements IWpfService.Initialize
        _optionsUI.DataContext = Me
    End Sub
#End Region

    Public Sub Start() Implements IWpfService.Start
        _optionsUI.DataContext = Me

        If Not OperatingSystemUtil.MeetsOrExceedsWin7() Then
            ' Fatal error
            Throw New UtilityRuntimeException("This addin requires Windows 7 or higher to operate")
        Else
            gps = New LatLongLocationProvider(30000)

            LocationProvider.RequestPermissions(IntPtr.Zero, True, gps)
        End If

        Status = "Time zone Changer Started"
    End Sub

    Private updating As Boolean = False
    Sub gps_LocationChanged(ByVal locationProvider As LocationProvider, ByVal newLocation As LocationReport) Handles gps.LocationChanged
        If Not updating Then
            updating = True
            Try
                ' TODO: Somehow check for larger changes... don't respond to every movement
                LastDataReport = TryCast(newLocation, LatLongLocationReport)
                Dim newTZ As TimeZoneInfo = TimeZoneLocationService.GetTimeZoneInfoByCoordinates(LastDataReport.Latitude, LastDataReport.Longitude)

                If newTZ Is Nothing Then
                    Status = "No system time zone found for this region."
                Else
                    If TaskDialogSupport.MessagePrompt(newTZ) Then
                        DynamicTimeZoneInterop.SetDynamicTimeZone(newTZ)
                        Status = "Time zone updated to " + newTZ.DisplayName
                    End If
                End If
            Catch x As Exception
                Status = "Time zone update failed. (" + x.Message + ")"
            Finally
                updating = False
            End Try
        End If
    End Sub

    Private Function LookupLocation(ByVal latitude As Double, ByVal longitude As Double) As System.Nullable(Of Double)
        Dim utc As System.Nullable(Of Double) = TimeZoneLocationService.GetBaseUtcOffsetByCoordinates(latitude, longitude)

        Dim tzi As Double = DynamicTimeZoneInterop.GetDynamicTimeZone().bias / 60 * -1

        If utc Is Nothing Then
            Status = "No information found for your current location."
            Return Nothing
        ElseIf utc = tzi Then
            Status = "Still in the same time zone..."
            Return Nothing
        Else
            Return utc
        End If
    End Function

    Private Function FindTimezonesByBaseUtc(ByVal baseUtcOffset As Double) As TimeZoneInfo
        Dim newTZ As TimeZoneInfo = Nothing

        ' This join does not take into account matching the daylight savings offset
        ' since daylight savings dates are in a sub-collection...
        Dim tz As TimeZoneInfo() = (From ctz In TimeZoneInfo.GetSystemTimeZones() _
         Where ctz.BaseUtcOffset.TotalHours = baseUtcOffset _
         Select ctz).ToArray()

        If tz.Length = 1 Then
            ' Set time zone (and confirm status)
            If TaskDialogSupport.MessagePrompt(tz(0)) Then
                newTZ = tz(0)
            End If
        ElseIf tz.Length > 0 Then
            newTZ = tzPicker.Prompt(tz)
        End If

        Return newTZ
    End Function

    Private _lastDataReport As LatLongLocationReport
    Public Property LastDataReport() As LatLongLocationReport
        Get
            Return _lastDataReport
        End Get
        Set(ByVal value As LatLongLocationReport)
            _lastDataReport = value
            OnPropertyChanged("LastDataReport")
        End Set
    End Property

    Public Sub [Stop]() Implements IWpfService.Stop
        ' TODO: Detach from location provider
        Status = "TimeZone changer Stopped"
    End Sub

#Region "INotifyPropertyChanged Members"

    Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged

    Private Sub OnPropertyChanged(ByVal prop As String)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(prop))
    End Sub
#End Region
End Class
